#include "timer.h"
#include "util.h"

namespace johnsonli
{
    bool Timer::Comperator::operator()(const Timer::ptr& lhs, const Timer::ptr& rhs) const
    {
        //左右都为null
        if(!lhs && !lhs)
        {
            return false;
        }

        //空的，默认小
        if(!lhs)
        {
            return true;
        }
        if(!rhs)
        {
            return false;
        }

        //左<右，true; 左>右，false
        if(lhs->m_next < rhs->m_next)
        {
            return true;
        }
        if(lhs->m_next > rhs->m_next)
        {
            return false;
        }
        
        //左右相同，比较地址
        return lhs.get() < rhs.get();
    }

    Timer::Timer(uint64_t ms, std::function<void()> cb, bool recurring, TimerManager* manager)
        :m_recurring(recurring)
        ,m_ms(ms)
        ,m_cb(cb)
        ,m_manager(manager)
    {
         //std::cout << "Timer: " << GetCurrentMS() <<std::endl;
        m_next = GetCurrentMS() + m_ms;
    }

    Timer::Timer(uint64_t next)
        :m_next(next)
    {}

    bool Timer::cancel()
    {
        TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex);
        if(m_cb)
        {
            m_cb = nullptr;
            auto it = m_manager->m_timers.find(shared_from_this());
            if(it == m_manager->m_timers.end()) {
                return false;
            }
            m_manager->m_timers.erase(it);
            return true;
        }

        //没有回调函数，说明已经被执行了
        return false;
    }

    bool Timer::refresh()
    {
        TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex);
        if(!m_cb)
        {
            return false;
        }

        //当前定时器没找到
        auto it = m_manager->m_timers.find(shared_from_this());
        if(it == m_manager->m_timers.end()) {
            return false;
        }

        //删除该定时器
        m_manager->m_timers.erase(it);
        //重新设置时间，再加入
        m_next = johnsonli::GetCurrentMS() + m_ms;

        m_manager->addTimer(shared_from_this(), lock);

        return true;

    }

    bool Timer::reset(uint64_t ms, bool from_now)
    {   
        //周期相同，并且不从当前时间开始
        if(ms == m_ms && !from_now) {
            return true;
        }

        TimerManager::RWMutexType::WriteLock lock(m_manager->m_mutex);
        
        //没有回调
        if(!m_cb) {
            return false;
        }

        //没找到不操作，找到了删除
        auto it = m_manager->m_timers.find(shared_from_this());
        if(it == m_manager->m_timers.end()) {
            return false;
        }
        m_manager->m_timers.erase(it);

        uint64_t start = 0;
        if(from_now) {
            //从当前开始
            start = johnsonli::GetCurrentMS();
        } else {
            //不从当前开始，使用之前的起始时间
            start = m_next - m_ms;
        }

        //reset后重新加入
        m_ms = ms;
        m_next = start + m_ms;

        m_manager->addTimer(shared_from_this(), lock);
        return true;

    }

    TimerManager::TimerManager()
    {

    }

    TimerManager::~TimerManager()
    {

    }

    Timer::ptr TimerManager::addTimer(uint64_t ms, std::function<void()> cb
                    ,bool recurring)
    {
        Timer::ptr timer(new Timer(ms, cb, recurring, this));
        RWMutexType::WriteLock lock(m_mutex);
        
        addTimer(timer, lock);
        
        return timer;
    }

    static void OnTimer(std::weak_ptr<void> weak_cond, std::function<void()> cb)
    {
        //当wealk ptr还有计数时，lock才会返回其智能指针，否则tmp为空
        std::shared_ptr<void> tmp = weak_cond.lock();
        if(tmp)
        {
            cb();
        }
    }

    //weak_cond：满足条件再执行，智能指针=0时，就不触发
    Timer::ptr TimerManager::addConditionTimer(uint64_t ms, std::function<void()> cb
                    ,std::weak_ptr<void> weak_cond
                    ,bool recurring)
    {
        return addTimer(ms, std::bind(&OnTimer, weak_cond, cb), recurring);
    }

    void TimerManager::addTimer(Timer::ptr val, RWMutexType::WriteLock& lock) 
    {
        auto it = m_timers.insert(val).first;

        //他是第一个，并且还没有通知
        bool at_front = (it == m_timers.begin()) && !m_tickled;
        
        //让他通知
        if(at_front) {
            m_tickled = true;
        }
        lock.unlock();
        //加到第一个要执行
        if(at_front) {
            onTimerInsertedAtFront();
        }
    }

    uint64_t TimerManager::getNextTimer()
    {
        RWMutexType::ReadLock lock(m_mutex);
        
        //没有定时器，最大值
        if(m_timers.empty())
        {
            return ~0ull;
        }

        //最近执行的定时器
        const Timer::ptr& next = *m_timers.begin();
        uint64_t now_ms = johnsonli::GetCurrentMS();

        //std::cout << "getNextTimer: " << now_ms <<std::endl;

        //当前时间 比 最近执行定时器时间大，说明这个定时器不知道什么原因，导致没有执行，返回0
        if(now_ms >= next->m_next)
        {
            return 0;
        }
        else
        {
            return next->m_next - now_ms;
        }
    }

    void TimerManager::listExpiredCb(std::vector<std::function<void()>>& cbs)
    {
        uint64_t now_ms = johnsonli::GetCurrentMS();
        
        std::vector<Timer::ptr> expired;
        
        {
            RWMutexType::ReadLock lock(m_mutex);
            //没有就操作
            if(m_timers.empty())
            {
                return;
            }
        }

        bool rollover = detectClockRollover(now_ms);
        if(!rollover && ((*m_timers.begin())->m_next > now_ms)) {
            return;
        }

        RWMutexType::WriteLock lock(m_mutex);
        Timer::ptr now_timer(new Timer(now_ms));
        auto it = rollover ? m_timers.end() : m_timers.lower_bound(now_timer);  //服务器时间调整了，就到最后；没调整，找到第一个不小于（>=）now_timer的值
        while(it != m_timers.end() && (*it)->m_next == now_ms)  //可能有值相等的情况，需要往后继续走，找到第一个>now_timer的值
        {
            ++it;
        }

        expired.insert(expired.begin(), m_timers.begin(), it);  //将<= now_timer的都加到expired
        m_timers.erase(m_timers.begin(), it);   //删除
        
        //加回调
        cbs.reserve(expired.size());
        for(auto& timer : expired)
        {
            cbs.push_back(timer->m_cb);
            
            //如果是循环定时，需要再加回到m_timers
            if(timer->m_recurring)
            {
                timer->m_next = now_ms + timer->m_ms;
                addTimer(timer, lock);
            }
            else
            {
                timer->m_cb = nullptr;  //防止m_cb中有智能指针，不置空，永远有计数
            }
        }

    }
    
    bool TimerManager::detectClockRollover(uint64_t now_ms)
    {
        bool rollover = false;
        //当前时间比之前的时间还小，说明服务器时间被调前了
        if(now_ms < m_previouseTime && now_ms < (m_previouseTime - 60 * 60 * 1000))
        {
            rollover = true;
        }
        m_previouseTime = now_ms;
        return rollover;
    }
}
